package com.nyp.remoter.ejb;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.ListJoin;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;

import com.nyp.remoter.entity.Cat;
import com.nyp.remoter.entity.CatDogFight;
import com.nyp.remoter.entity.CatDogFight_;
import com.nyp.remoter.entity.Cat_;
import com.nyp.remoter.entity.Dog;
import com.nyp.remoter.entity.Dog_;
import com.nyp.remoter.entity.User;
import com.nyp.remoter.entity.User_;

@Stateless
public class SearchEJB implements SearchService{
	
	@PersistenceContext
	EntityManager em;
	
	@Inject Logger logger;
	
	@Override
	public List<User> searchUser(User userFilter){
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<User> cQuery = cb.createQuery(User.class);
		Root<User> u = cQuery.from(User.class);
		List<Predicate> predicates = new ArrayList<Predicate>();
		if(StringUtils.isNotBlank(userFilter.getName())){
			predicates.add(cb.like(u.get(User_.name), "%"+ userFilter.getName() +"%"));
		}
		if(StringUtils.isNotBlank(userFilter.getMotherName())){
			predicates.add(cb.like(u.get(User_.motherName), "%"+ userFilter.getMotherName() +"%"));
		}
		if(userFilter.getId() != null && !new Long(0).equals(userFilter.getId())){
			predicates.add(cb.equal(u.get(User_.id), userFilter.getId()));
		}
		if(StringUtils.isNotBlank(userFilter.getProfession())){
			predicates.add(cb.like(u.get(User_.profession), "%"+ userFilter.getProfession() +"%"));
		}
		
		Predicate[] prArray = {};
		cQuery.where(predicates.toArray(prArray));
		List<User> resultList = em.createQuery(cQuery).getResultList();
		for (User user : resultList) {
			logger.info(user.toString());
		}
		return resultList;
	}
	
	@Override
	public List<Cat> searchCatsChasedByDog(Long dogId){
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Cat> cQuery = cb.createQuery(Cat.class);
		Root<Cat> c = cQuery.from(Cat.class);
		cQuery.select(c);
		ListJoin<Cat, CatDogFight> fight = c.join(Cat_.fights, JoinType.INNER);
		Join<CatDogFight, Dog> d = fight.join(CatDogFight_.dog, JoinType.INNER);
		cQuery.where(cb.equal(d.get(Dog_.id), dogId));
		
		List<Cat> ret = em.createQuery(cQuery).getResultList();
		return ret;
	}
	
	@Override
	public List<User> searchUserWithCats(User userFilter){
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<User> cQuery = cb.createQuery(User.class);
		Root<User> user = cQuery.from(User.class);
		ListJoin<User, Cat> cats = user.join(User_.cats);
		cQuery.select(user);
		
		cQuery.where(cb.and(
				cb.like(user.get(User_.name), "%Mézga%"),
				cb.like(cats.get(Cat_.name), "%Maffia%"))
				);
		cQuery.orderBy(
				cb.desc(user.get(User_.name)),
				cb.desc(user.get(User_.dateOfBirth))
				);
		List<User> resultList = em.createQuery(cQuery).getResultList();
		for (User u : resultList) {
			logger.debug(u.toString());
		}
		return resultList;
	}
	
	public List<Object> searchUsersByProfession(){
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Object> cQuery = cb.createQuery();
		Root<User> userRoot = cQuery.from(User.class);
		cQuery.multiselect(
				cb.count(userRoot.get(User_.id)), 
				userRoot.get(User_.profession));
		cQuery.groupBy(userRoot.get(User_.profession));
		cQuery.having(cb.gt(cb.count(userRoot.get(User_.id)), 2));
		List<Object> resultList = em.createQuery(cQuery).getResultList();
		return resultList;
	}

}
